﻿namespace Fiddler
{
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Cache;
    using System.Runtime.InteropServices;
    using System.Text;

    internal class FTPGateway
    {
        public static void MakeFTPRequest(Session oSession, ref PipeReadBuffer buffBody, out HTTPResponseHeaders oRH)
        {
            FtpWebResponse response;
            if ((oSession.oRequest == null) || (oSession.oRequest.headers == null))
            {
                throw new ArgumentException("Session missing request objects.");
            }
            if (buffBody == null)
            {
                throw new ArgumentException("Response Stream may not be null.");
            }
            string fullUrl = oSession.fullUrl;
            FtpWebRequest request = (FtpWebRequest) WebRequest.Create(fullUrl);
            request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
            if (fullUrl.EndsWith("/"))
            {
                request.Method = "LIST";
            }
            else
            {
                request.Method = "RETR";
                if (oSession.oFlags.ContainsKey("FTP-UseASCII"))
                {
                    request.UseBinary = false;
                }
                else
                {
                    request.UseBinary = FiddlerApplication.Prefs.GetBoolPref("fiddler.ftp.UseBinary", true);
                }
            }
            if (!string.IsNullOrEmpty(oSession.oRequest.headers._uriUserInfo))
            {
                string sString = Utilities.UrlDecode(Utilities.TrimAfter(oSession.oRequest.headers._uriUserInfo, '@'));
                string userName = Utilities.TrimAfter(sString, ':');
                string password = sString.Contains(":") ? Utilities.TrimBefore(sString, ':') : string.Empty;
                request.Credentials = new NetworkCredential(userName, password);
            }
            else if (oSession.oRequest.headers.ExistsAndContains("Authorization", "Basic "))
            {
                string s = oSession.oRequest.headers["Authorization"].Substring(6);
                s = Encoding.UTF8.GetString(Convert.FromBase64String(s));
                string str6 = Utilities.TrimAfter(s, ':');
                string str7 = Utilities.TrimBefore(s, ':');
                request.Credentials = new NetworkCredential(str6, str7);
            }
            else if (oSession.oFlags.ContainsKey("x-AutoAuth") && oSession.oFlags["x-AutoAuth"].Contains(":"))
            {
                string str8 = Utilities.TrimAfter(oSession.oFlags["x-AutoAuth"], ':');
                string str9 = Utilities.TrimBefore(oSession.oFlags["x-AutoAuth"], ':');
                request.Credentials = new NetworkCredential(str8, str9);
            }
            else if (FiddlerApplication.Prefs.GetBoolPref("fiddler.ftp.AlwaysDemandCredentials", false))
            {
                byte[] bytes = Encoding.UTF8.GetBytes("Please provide login credentials for this FTP server".PadRight(0x200, ' '));
                buffBody.Write(bytes, 0, bytes.Length);
                oRH = new HTTPResponseHeaders();
                oRH.HTTPResponseCode = 0x191;
                oRH.HTTPResponseStatus = "401 Need Creds";
                oRH.Add("Content-Length", buffBody.Length.ToString());
                oRH.Add("WWW-Authenticate", "Basic realm=\"ftp://" + oSession.host + "\"");
                return;
            }
            request.UsePassive = FiddlerApplication.Prefs.GetBoolPref("fiddler.ftp.UsePassive", true);
            request.Proxy = null;
            try
            {
                response = (FtpWebResponse) request.GetResponse();
            }
            catch (WebException exception)
            {
                byte[] buffer2;
                FtpWebResponse response2 = (FtpWebResponse) exception.Response;
                if (response2 != null)
                {
                    if (FtpStatusCode.NotLoggedIn == response2.StatusCode)
                    {
                        buffer2 = Encoding.UTF8.GetBytes("This FTP server requires login credentials".PadRight(0x200, ' '));
                        buffBody.Write(buffer2, 0, buffer2.Length);
                        oRH = new HTTPResponseHeaders();
                        oRH.HTTPResponseCode = 0x191;
                        oRH.HTTPResponseStatus = "401 Need Creds";
                        oRH.Add("Content-Length", buffBody.Length.ToString());
                        oRH.Add("WWW-Authenticate", "Basic realm=\"ftp://" + oSession.host + "\"");
                        return;
                    }
                    buffer2 = Encoding.UTF8.GetBytes(string.Format("{0}{1}{2}", "Fiddler was unable to act as a HTTP-to-FTP gateway for this response. ", response2.StatusDescription, string.Empty.PadRight(0x200, ' ')));
                    buffBody.Write(buffer2, 0, buffer2.Length);
                }
                else
                {
                    buffer2 = Encoding.UTF8.GetBytes(string.Format("{0}{1}{2}", "Fiddler was unable to act as a HTTP-to-FTP gateway for this response. ", exception.Message, string.Empty.PadRight(0x200, ' ')));
                    buffBody.Write(buffer2, 0, buffer2.Length);
                }
                oRH = new HTTPResponseHeaders();
                oRH.HTTPResponseCode = 0x1f8;
                oRH.HTTPResponseStatus = "504 HTTP-FTP Gateway failed";
                oRH.Add("Content-Length", buffBody.Length.ToString());
                return;
            }
            Stream responseStream = response.GetResponseStream();
            byte[] buffer3 = new byte[0x2000];
            for (int i = responseStream.Read(buffer3, 0, 0x2000); i > 0; i = responseStream.Read(buffer3, 0, 0x2000))
            {
                buffBody.Write(buffer3, 0, i);
            }
            oRH = new HTTPResponseHeaders();
            oRH.HTTPResponseCode = 200;
            oRH.HTTPResponseStatus = "200 OK";
            oRH.Add("FTP-Status", Utilities.ConvertCRAndLFToSpaces(response.StatusDescription));
            oRH.Add("Content-Length", buffBody.Length.ToString());
            response.Close();
        }
    }
}

